package squidpony.squidgrid.gui.gdx;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetDescriptor;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Disposable;
import squidpony.IColorCenter;
import squidpony.squidmath.OrderedMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import static squidpony.squidgrid.gui.gdx.SColor.colorFromFloat;
/**
* Class for creating text blocks.
*
* This class defaults to having no padding and having no font set. You can use a
* default square or narrow font by calling the appropriate method, or set the font
* to any AngelCode bitmap font on the classpath (typically in libGDX, this would be
* in the assets folder; these fonts can be created by Hiero in the libGDX tools,
* see https://github.com/libgdx/libgdx/wiki/Hiero for more)
*
* After all settings are set, one of the initialization methods must be called
* before the factory can be used.
*
* In order to easily support Unicode, strings are treated as a series of code
* points.
*
* All images have transparent backgrounds.
*
* @author Eben Howard - http://squidpony.com - howard@squidpony.com
* @author Tommy Ettinger
*/
public class TextCellFactory implements Disposable {
/**
* The commonly used symbols in roguelike games.
*/
public static final String DEFAULT_FITTING = "@!#$%^&*()_+1234567890-=~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;:,'\"{}?/\\ ",
LINE_FITTING = "┼├┤┴┬┌┐└┘│─",
SQUID_FITTING = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmno"+
"pqrstuvwxyz{|}~¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàá"+
"âãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİı"+
"IJijĴĵĶķĹĺĻļĽľĿŀŁłŃńŅņŇňŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƒǺǻǼǽǾ"+
"ǿȘșȚțȷˆˇˉˋ˘˙˚˛˜˝;΄΅Ά·ΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυ"+
"φχψωϊϋόύώЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхц"+
"чшщъыьэюяѐёђѓєѕіїјљњћќѝўџѢѣѲѳѴѵҐґẀẁẂẃẄẅỲỳ–—‘’‚‛“”„†‡•…‰‹›ⁿ₤€№™Ω℮←↑→↓∆−√≈─│┌┐└┘├┤"+
"┬┴┼═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫■□▪▫▲▼◊○●◦♀♂♠♣♥♦♪";
/**
* The {@link AssetManager} from where to load the font. Use it to share
* loading of a font's file across multiple factories.
*/
protected /* Nullable */AssetManager assetManager;
public BitmapFont bmpFont = null;
protected Texture block = null;
protected TextureRegion dirMarker = null;
protected String fitting = SQUID_FITTING;
protected IColorCenter<Color> scc;
protected int leftPadding = 0, rightPadding = 0, topPadding = 0, bottomPadding = 0;
protected float width = 1, height = 1;
protected float actualCellWidth = 1, actualCellHeight = 1;
protected float distanceFieldScaleX = 36f, distanceFieldScaleY = 36f;
private boolean initialized = false, initializedByFont = false, initializedBySize = false;
protected boolean distanceField = false;
protected ShaderProgram shader;
protected float smoothingMultiplier = 1f;
protected float descent, lineHeight;
private Label.LabelStyle style;
protected OrderedMap<Character, Character> swap = new OrderedMap<>(32);
protected char directionGlyph = '^';
protected OrderedMap<Character, TextureRegion> glyphTextures = new OrderedMap<>(16);
private StringBuilder mut = new StringBuilder(1).append('\0');
/**
* Creates a default valued factory. One of the initialization methods must
* be called before this factory can be used!
*/
public TextCellFactory() {
this(null);
}
/**
* A default valued factory that uses the given {@link AssetManager} to load
* the font file. Use this constructor if you are likely to load the same
* font over and over (recall that, without an {@link AssetManager}, each
* instance of {@link TextCellFactory} will load its font from disk). This
* primarily matters if you are using fonts not bundled with SquidLib, since
* accessing a BitmapFont with a method (not a String) from DefaultResources
* caches the BitmapFont already.
*
* @param assetManager an ordinary libGDX AssetManager
*/
public TextCellFactory(/* Nullable */ AssetManager assetManager) {
this.assetManager = assetManager;
scc = DefaultResources.getSCC();
swap.put('\u0006', ' ');
}
public TextCellFactory copy()
{
TextCellFactory next = new TextCellFactory(assetManager);
//next.bmpFont = bmpFont;
if(bmpFont == null)
bmpFont = DefaultResources.getIncludedFont();
next.bmpFont = new BitmapFont(new BitmapFont.BitmapFontData(bmpFont.getData().getFontFile(), false),
bmpFont.getRegions(), bmpFont.usesIntegerPositions());
next.block = block;
next.swap = new OrderedMap<>(swap);
next.distanceField = distanceField;
next.distanceFieldScaleX = distanceFieldScaleX;
next.distanceFieldScaleY = distanceFieldScaleY;
next.shader = null;
next.fitting = fitting;
next.height = height;
next.width = width;
next.actualCellWidth = actualCellWidth;
next.actualCellHeight = actualCellHeight;
next.descent = descent;
next.lineHeight = lineHeight;
//next.modifiedHeight = modifiedHeight;
next.smoothingMultiplier = smoothingMultiplier;
next.scc = scc;
next.directionGlyph = directionGlyph;
if(initializedBySize)
next.initBySize();
else if(initializedByFont)
next.initByFont();
return next;
}
/**
* Initializes the factory to then be able to create text cells on demand.
*
* Will match the width and height to 12 and 12, scaling the font to fit.
*
* Calling this after the factory has already been initialized will
* re-initialize it.
*
* @return this for method chaining
*/
public TextCellFactory initByFont() {
if(bmpFont == null)
bmpFont = DefaultResources.getIncludedFont();
bmpFont.setFixedWidthGlyphs(fitting);
width = bmpFont.getSpaceWidth();
lineHeight = bmpFont.getLineHeight();
height = (lineHeight);
descent = bmpFont.getDescent();
actualCellWidth = width;
actualCellHeight = height;
//modifiedHeight = height;
Pixmap temp = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
temp.setColor(Color.WHITE);
temp.fill();
block = new Texture(1, 1, Pixmap.Format.RGBA8888);
block.draw(temp, 0, 0);
temp.dispose();
style = new Label.LabelStyle(bmpFont, null);
BitmapFont.Glyph g = bmpFont.getData().getGlyph(directionGlyph);
dirMarker = new TextureRegion(bmpFont.getRegion(g.page), g.srcX, g.srcY, g.width, g.height);
initialized = true;
initializedByFont = true;
return this;
}
/**
* Initializes the factory to then be able to create text cells on demand.
*
* Will strictly use the provided width and height values to size the cells.
*
* Calling this after the factory has already been initialized will
* re-initialize it.
*
* @return this for method chaining
*/
public TextCellFactory initBySize() {
if(bmpFont == null)
bmpFont = DefaultResources.getIncludedFont();
//bmpFont.setFixedWidthGlyphs(fitting);
Pixmap temp = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
temp.setColor(Color.WHITE);
temp.fill();
block = new Texture(1, 1, Pixmap.Format.RGBA8888);
block.draw(temp, 0, 0);
temp.dispose();
if(distanceField)
{
bmpFont.getData().setScale(width / distanceFieldScaleX, height / distanceFieldScaleY);
shader = new ShaderProgram(DefaultResources.vertexShader, DefaultResources.fragmentShader);
if (!shader.isCompiled()) {
Gdx.app.error("shader", "Distance Field font shader compilation failed:\n" + shader.getLog());
}
lineHeight = bmpFont.getLineHeight();
//lineTweak = lineHeight / 20f;
//distanceFieldScaleX *= (((float)width) / height) / (distanceFieldScaleX / distanceFieldScaleY);
}
else {
shader = SpriteBatch.createDefaultShader();
lineHeight = bmpFont.getLineHeight();
//lineTweak = lineHeight * 0.0625f;
}
descent = bmpFont.getDescent();
style = new Label.LabelStyle(bmpFont, null);
BitmapFont.Glyph g = bmpFont.getData().getGlyph(directionGlyph);
dirMarker = new TextureRegion(bmpFont.getRegion(g.page), g.srcX, g.srcY, g.width, g.height);
initialized = true;
initializedBySize = true;
return this;
}
/**
* Initializes the factory to then be able to create text cells on demand.
*
* (This is identical to initBySize() when using libGDX.)
*
* @return this for method chaining
*/
public TextCellFactory initVerbatim() {
return initBySize();
}
/**
* Returns the font used by this factory.
*
* @return the font
*/
public BitmapFont font() {
return bmpFont;
}
/**
* Sets this factory to use the provided font.
*
* This is a way to complete a needed step; the font must be set before initializing, which can be done by a few
* methods in this class.
*
* This should be called with an argument such as "Rogue-Zodiac-6x12.fnt", that is, it should have the .fnt
* extension as opposed to the .png that accompanies such a bitmap font. The bitmap font should be either in the
* internal folder that libGDX knows about, which means it is in the assets folder of your project usually, or it
* can be on the classpath, which mostly applies to these resources bundled with SquidLib:
* <ul>
* <li>DefaultResources.squareName = "Zodiac-Square-12x12.fnt"</li>
* <li>DefaultResources.narrowName = "Rogue-Zodiac-6x12.fnt"</li>
* <li>DefaultResources.unicodeName = "Mandrill-6x16.fnt"</li>
* <li>DefaultResources.smoothName = "Inconsolata-LGC-8x18.fnt"</li>
* <li>DefaultResources.squareNameLarge = "Zodiac-Square-24x24.fnt"</li>
* <li>DefaultResources.narrowNameLarge = "Rogue-Zodiac-12x24.fnt"</li>
* <li>DefaultResources.unicodeNameLarge = "Mandrill-12x32.fnt"</li>
* <li>DefaultResources.smoothNameLarge = "Inconsolata-LGC-12x24.fnt"</li>
* <li>DefaultResources.narrowNameExtraLarge = "Rogue-Zodiac-18x36.fnt"</li>
* <li>There is also a sequence of resized versions of Inconsolata LGC, altered to fit in a square area. These
* don't have names in DefaultResources; you should use the overload of font() that takes a BitmapFont if you
* want to use the multiple, increasingly-resized versions.</li>
* </ul>
* "Rogue-Zodiac-12x24.fnt", which is easily accessed by the field DefaultResources.narrowNameLarge , can also
* be set using TextCellFactory.defaultNarrowFont() instead of font(). "Zodiac-Square-12x12.fnt", also accessible
* as DefaultResources.squareName , can be set using TextCellFactory.defaultSquareFont() instead of font().
* "Inconsolata-LGC-12x24.fnt", also accessible as DefaultResources.smoothNameLarge , can be set using
* TextCellFactory.defaultFont() instead of font(). All three of these alternatives will cache the BitmapFont if
* the same one is requested later, but this font() method will not.
* <br>
* See https://github.com/libgdx/libgdx/wiki/Hiero for some ways to create a bitmap font this can use. Several fonts
* in this list were created using Hiero (not Hiero4), and several were created with AngelCode's BMFont tool.
*
* @param fontpath the path to the font to use
* @return this factory for method chaining
*/
public TextCellFactory font(String fontpath) {
if (assetManager == null) {
if (Gdx.files.internal(fontpath).exists())
bmpFont = new BitmapFont(Gdx.files.internal(fontpath));
else if (Gdx.files.classpath(fontpath).exists())
bmpFont = new BitmapFont(Gdx.files.classpath(fontpath));
else
bmpFont = DefaultResources.getIncludedFont();
}
else {
assetManager.load(new AssetDescriptor<>(fontpath, BitmapFont.class));
/*
* We're using the AssetManager not be asynchronous, but to avoid
* loading a file twice (because that takes some time (tens of
* milliseconds)). Hence this KISS code to avoid having to handle a
* not-yet-loaded font:
*/
assetManager.finishLoading();
bmpFont = assetManager.get(fontpath, BitmapFont.class);
}
return this;
}
/**
* Sets this factory to use the provided BitmapFont as its font without re-constructing anything.
*
* This is a way to complete a needed step; the font must be set before initializing, which can be done by a few
* methods in this class.
*
* This should be called with an argument such as {@code DefaultResources.getDefaultFont()} or any other variable
* with BitmapFont as its type. The bitmap font will not be loaded from file with this method, which it would be if
* you called the overload of font() that takes a String more than once. These BitmapFont resources are already
* bundled with SquidLib:
* <ul>
* <li>DefaultResources.getDefaultFont() = "Zodiac-Square-12x12.fnt"</li>
* <li>DefaultResources.getDefaultNarrowFont() = "Rogue-Zodiac-6x12.fnt"</li>
* <li>DefaultResources.getDefaultUnicodeFont() = "Mandrill-6x16.fnt"</li>
* <li>DefaultResources.getSmoothFont() = "Inconsolata-LGC-8x18.fnt"</li>
* <li>DefaultResources.getLargeFont() = "Zodiac-Square-24x24.fnt"</li>
* <li>DefaultResources.getLargeNarrowFont() = "Rogue-Zodiac-12x24.fnt"</li>
* <li>DefaultResources.getLargeUnicodeFont() = "Mandrill-12x32.fnt"</li>
* <li>DefaultResources.getLargeSmoothFont() = "Inconsolata-LGC-12x24.fnt"</li>
* <li>DefaultResources.getExtraLargeNarrowFont() = "Rogue-Zodiac-18x36.fnt"</li>
* <li>There is also a sequence of resized versions of Inconsolata LGC, altered to fit in a square area. These
* can be accessed with DefaultResources.getZoomedFont(), passing an int between 0 and 11 inclusive.</li>
* </ul>
* "Rogue-Zodiac-12x24.fnt", which is easily accessed by the method DefaultResources.getLargeNarrowFont() , can also
* be set using TextCellFactory.defaultNarrowFont() instead of font(). "Zodiac-Square-12x12.fnt", also accessible
* with DefaultResources.getDefaultFont() , can be set using TextCellFactory.defaultSquareFont() instead of font().
* "Inconsolata-LGC-12x24.fnt", also accessible with DefaultResources.getLargeSmoothFont() , can be set using
* TextCellFactory.defaultFont() instead of font(). All three of these alternatives will cache the BitmapFont if
* the same one is requested later, but this font() method will not.
* <br>
* See https://github.com/libgdx/libgdx/wiki/Hiero for some ways to create a bitmap font this can use. Several fonts
* in this list were created using Hiero (not Hiero4), and several were created with AngelCode's BMFont tool.
*
* @param bitmapFont the BitmapFont this should use
* @return this factory for method chaining
*/
public TextCellFactory font(BitmapFont bitmapFont) {
if (bitmapFont == null) {
bmpFont = DefaultResources.getIncludedFont();
}
else {
bmpFont = bitmapFont;
}
return this;
}
/**
* Sets the font to a distance field font with the given String path to a .fnt file and String path to a texture.
* Distance field fonts should scale cleanly to multiple resolutions without artifacts. Does not use AssetManager
* since you shouldn't need to reload the font if it scales with one image. You need to configure the shader to use
* distance field fonts unless a class already does this for you (SquidLayers handles shader configuration
* internally, for example). TextCellFactory has a method, configureShader(Batch), that does this and should be
* called while that Batch has begun rendering, typically in an override of some containing Scene2D Group's
* draw(Batch, float) method.
* <br>
* At least two distance field fonts are included in SquidLib; one is square, one is narrow, and they can both be
* accessed using either the predefined TextCellFactory objects in DefaultResources, accessible with
* getStretchableFont() for narrow or getStretchableSquareFont() for square, or the setter methods in this class,
* defaultDistanceFieldFont() for square and defaultNarrowDistanceFieldFont() for narrow.
* <br>
* To create distance field fonts that work well with monospace layout is... time-consuming and error-prone, though
* not especially difficult for most fonts. The process is documented as well as we can, given how differently all
* fonts are made, in a file not included in the distribution JAR but present on GitHub:
* https://github.com/SquidPony/SquidLib/blob/master/squidlib/etc/making-distance-field-fonts.txt
* @param fontPath the path to a .fnt bitmap font file with distance field effects applied, which requires a complex
* process to create.
* @param texturePath the path to the texture used by the bitmap font
* @return this factory for method chaining
*/
public TextCellFactory fontDistanceField(String fontPath, String texturePath) {
Texture tex;
if (Gdx.files.internal(texturePath).exists()) {
Gdx.app.debug("font", "Using internal font texture at " + texturePath);
tex = new Texture(Gdx.files.internal(texturePath), true);
tex.setFilter(Texture.TextureFilter.MipMapLinearNearest, Texture.TextureFilter.Linear);
} else if (Gdx.files.classpath(texturePath).exists()) {
Gdx.app.debug("font", "Using classpath font texture at " + texturePath);
tex = new Texture(Gdx.files.classpath(texturePath), true);
tex.setFilter(Texture.TextureFilter.MipMapLinearNearest, Texture.TextureFilter.Linear);
} else {
bmpFont = DefaultResources.getIncludedFont();
Gdx.app.error("TextCellFactory", "Could not find font file: " + texturePath + ", using defaults");
return this;
}
if (Gdx.files.internal(fontPath).exists()) {
Gdx.app.debug("font", "Using internal font at " + fontPath);
bmpFont = new BitmapFont(Gdx.files.internal(fontPath), new TextureRegion(tex), false);
distanceField = true;
} else if (Gdx.files.classpath(fontPath).exists()) {
Gdx.app.debug("font", "Using classpath font at " + fontPath);
bmpFont = new BitmapFont(Gdx.files.classpath(fontPath), new TextureRegion(tex), false);
distanceField = true;
} else {
bmpFont = DefaultResources.getIncludedFont();
Gdx.app.error("TextCellFactory", "Could not find font file: " + fontPath + ", using defaults");
}
//bmpFont.getData().padBottom = bmpFont.getDescent();
distanceFieldScaleX = bmpFont.getSpaceWidth() - 1f;
distanceFieldScaleY = bmpFont.getLineHeight() - 1f;
return this;
}
/**
* Sets this factory to use the one font included with libGDX, which is Arial at size 15 px. Does it correctly
* display when used in a grid? Probably not as well as you'd hope. You should probably get some of the assets that
* accompany SquidLib, and can be downloaded directly from GitHub (not available as one monolithic jar via Maven
* Central, but that lets you pick and choose individual assets). Get a .fnt and its matching .png file from
* https://github.com/SquidPony/SquidLib/tree/master/assets and you can pass them to {@link #font(String)} or
* {@link #fontDistanceField(String, String)}.
*
* @return this factory for method chaining
*/
public TextCellFactory includedFont()
{
bmpFont = DefaultResources.getIncludedFont();
return this;
}/**
* Sets this factory to use a default 12x24 font that supports Latin, Greek, Cyrillic, and many more, including
* box-drawing characters, zodiac signs, playing-card suits, and chess piece symbols. This is enough to support the
* output of anything that DungeonUtility can make for a dungeon or FakeLanguageGen can make for text with its
* defaults, which is difficult for any font to do. The box-drawing characters in this don't quite line up, and in
* some colors there may appear to be gaps (white text on black backgrounds will show it, but not much else).
*
* This is a way to complete a needed step; the font must be set before initializing, which can be done by a few
* methods in this class.
*
* @return this factory for method chaining
*/
public TextCellFactory defaultFont()
{
bmpFont = DefaultResources.getLargeSmoothFont();
return this;
}
/**
* Sets this factory to use a default 12x24 font that renders very accurately, with no gaps between box-drawing
* characters and very geometric lines.
*
* This is a way to complete a needed step; the font must be set before initializing, which can be done by a few
* methods in this class.
*
* @return this factory for method chaining
*/
public TextCellFactory defaultNarrowFont()
{
bmpFont = DefaultResources.getLargeNarrowFont();
return this;
}
/**
* Sets this factory to use a default 12x12 font, which... is square, and doesn't look as bad as many square fonts
* do, plus it supports box-drawing characters with no gaps.
*
* This is a way to complete a needed step; the font must be set before initializing, which can be done by a few
* methods in this class.
*
* @return this factory for method chaining
*/
public TextCellFactory defaultSquareFont()
{
bmpFont = DefaultResources.getDefaultFont();
return this;
}
/**
* Sets the TextCellFactory to use a square distance field font that will resize to whatever size you request.
* You must configure the shader if you use a distance field font, unless a class does it for you, like SquidLayers.
* The configureShader(Batch) method of this class can be used to set up the shader if you don't use SquidLayers;
* see its docs for more information.
* @return this TextCellFactory set to use a square distance field font
*/
public TextCellFactory defaultDistanceFieldFont()
{
fontDistanceField(DefaultResources.distanceFieldSquare, DefaultResources.distanceFieldSquareTexture);
return this;
}
/**
* Sets the TextCellFactory to use a half-square distance field font that will resize to whatever size you request.
* You must configure the shader if you use a distance field font, unless a class does it for you, like SquidLayers.
* The configureShader(Batch) method of this class can be used to set up the shader if you don't use SquidLayers;
* see its docs for more information.
* @return this TextCellFactory set to use a half-square distance field font
*/
public TextCellFactory defaultNarrowDistanceFieldFont()
{
fontDistanceField(DefaultResources.distanceFieldNarrow, DefaultResources.distanceFieldNarrowTexture);
return this;
}
/**
* Returns the width of a single cell.
*
* @return the width
*/
public float width() {
return width;
}
/**
* Sets the factory's cell width to the provided value. Clamps at 1 on the
* lower bound to ensure valid calculations.
*
* @param width the desired width
* @return this factory for method chaining
*/
public TextCellFactory width(float width) {
this.width = Math.max(1, width);
actualCellWidth = this.width;
return this;
}
/**
* Returns the height of a single cell.
*
* @return the height of a single cell
*/
public float height() {
return height;
}
/**
* Sets the factory's cell height to the provided value. Clamps at 1 on the
* lower bound to ensure valid calculations.
*
* @param height the desired width
* @return this factory for method chaining
*/
public TextCellFactory height(float height) {
this.height = Math.max(1, height);
//modifiedHeight = this.height;
actualCellHeight = this.height;
return this;
}
/**
* Sets the factory's height used for text to the provided value, but does not change the size of a cell. Clamps at
* 1 on the lower bound to ensure valid calculations.
*
* @param width the desired width
* @return this factory for method chaining
*/
public TextCellFactory tweakWidth(float width) {
this.width = Math.max(1, width);
return this;
}
/**
* Sets the factory's height used for text to the provided value, but does not change the size of a cell. Clamps at
* 1 on the lower bound to ensure valid calculations.
*
* @param height the desired height
* @return this factory for method chaining
*/
public TextCellFactory tweakHeight(float height) {
this.height = Math.max(1, height);
//modifiedHeight = this.height;
return this;
}
/**
* Returns the current String of code points that are used for sizing the
* cells.
*
* Note that this is actually a set of codepoints and treating them as an
* array of chars might give undesired results.
*
* @return the String used for sizing calculations
*/
public String fit() {
return fitting;
}
/**
* Sets the characters that will be guaranteed to fit to the provided ones.
* This will override any previously set string.
*
* @param fit the String of code points to size to
* @return this factory for method chaining
*/
public TextCellFactory fit(String fit) {
fitting = fit;
bmpFont.setFixedWidthGlyphs(fitting);
width = bmpFont.getSpaceWidth();
return this;
}
/**
* Adds the code points in the string to the list of characters that will be
* guaranteed to fit.
*
* @param fit the String of code points to size to
* @return this factory for method chaining
*/
public TextCellFactory addFit(String fit) {
fitting += fit;
bmpFont.setFixedWidthGlyphs(fitting);
width = bmpFont.getSpaceWidth();
return this;
}
/**
* Returns whether this factory is currently set to do antialiasing on the
* characters rendered, which is always true.
*
* @return true if antialiasing is set
*/
public boolean antialias() {
return true;
}
/**
* All fonts will be rendered with antialiasing, this doesn't do anything.
*
* @param antialias ignored, will always use antialiasing
* @return this factory for method chaining
* @deprecated AA is the wave of the future!
*/
public TextCellFactory antialias(boolean antialias) {
return this;
}
/**
* Sets the amount of padding on all sides to the provided value.
*
* @param padding how much padding in pixels
* @return this for method chaining
*/
public TextCellFactory padding(int padding) {
leftPadding = padding;
rightPadding = padding;
topPadding = padding;
bottomPadding = padding;
return this;
}
/**
* Returns the padding on the left side.
*
* @return amount of padding in pixels
*/
public int leftPadding() {
return leftPadding;
}
/**
* Sets the amount of padding on the left side to the provided value.
*
* @param padding how much padding in pixels
* @return this for method chaining
*/
public TextCellFactory leftPadding(int padding) {
leftPadding = padding;
return this;
}
/**
* Returns the padding on the right side.
*
* @return amount of padding in pixels
*/
public int rightPadding() {
return rightPadding;
}
/**
* Sets the amount of padding on the right side to the provided value.
*
* @param padding how much padding in pixels
* @return this for method chaining
*/
public TextCellFactory rightPadding(int padding) {
rightPadding = padding;
return this;
}
/**
* Returns the padding on the top side.
*
* @return amount of padding in pixels
*/
public int topPadding() {
return topPadding;
}
/**
* Sets the amount of padding on the top side to the provided value.
*
* @param padding how much padding in pixels
* @return this for method chaining
*/
public TextCellFactory topPadding(int padding) {
topPadding = padding;
return this;
}
/**
* Returns the padding on the bottom side.
*
* @return amount of padding in pixels
*/
public int bottomPadding() {
return bottomPadding;
}
/**
* Sets the amount of padding on the bottom side to the provided value.
*
* @param padding how much padding in pixels
* @return this for method chaining
*/
public TextCellFactory bottomPadding(int padding) {
bottomPadding = padding;
return this;
}
/**
* @param icc
* The color center to use. Should not be {@code null}.
* @return {@code this}
* @throws NullPointerException
* If {@code icc} is {@code null}.
*/
public TextCellFactory setColorCenter(IColorCenter<Color> icc) {
if (icc == null)
/* Better fail now than later */
throw new NullPointerException(
"The color center should not be null in " + getClass().getSimpleName());
scc = icc;
return this;
}
/**
* Returns true if this factory is fully initialized and ready to build text cells.
*
* @return true if initialized
*/
public boolean initialized() {
return initialized;
}
/**
* Returns true if the given character will fit inside the current cell
* dimensions with the current font.
*
* ISO Control characters, non-printing characters and invalid unicode
* characters are all considered by definition to fit.
*
* @param codepoint the codepoint of the char in question
* @return true if the char will fit, or if it is non-printing in some way; false otherwise
*/
public boolean willFit(int codepoint) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (!Character.isValidCodePoint(codepoint) ||
(codepoint <= 0x001F) || (codepoint >= 0x007F && codepoint <= 0x009F)) // same as isIsoControl
{
return true;
}
return fitting.contains(String.valueOf(Character.toChars(codepoint)));
}
/**
* Use the specified Batch to draw a String (often just one char long) with the default color (white), with x and y
* determining the world-space coordinates for the upper-left corner.
*
* @param batch the LibGDX Batch to do the drawing
* @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead.
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
*/
public void draw(Batch batch, String s, float x, float y) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
// + descent * 3 / 2f
// - distanceFieldScaleY / 12f
//height - lineTweak * 2f
if (s == null || s.isEmpty() || s.charAt(0) == 0) {
batch.setColor(1f,1f,1f,1f);
batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // + descent * 1 / 3f
} else {
bmpFont.setColor(1f,1f,1f,1f);
mut.setCharAt(0, swap.getOrDefault(s.charAt(0), s.charAt(0)));
bmpFont.draw(batch, mut, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width, Align.center, false);
}
}
/**
* Use the specified Batch to draw a char with the default color (white), with x and y
* determining the world-space coordinates for the upper-left corner.
*
* @param batch the LibGDX Batch to do the drawing
* @param c the char to draw, often but not necessarily one char. Can be null to draw a solid block instead.
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
*/
public void draw(Batch batch, char c, float x, float y) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
// + descent * 3 / 2f
// - distanceFieldScaleY / 12f
//height - lineTweak * 2f
if (c == 0) {
batch.setColor(1f,1f,1f,1f);
batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // + descent * 1 / 3f
} else {
bmpFont.setColor(1f,1f,1f,1f);
mut.setCharAt(0, swap.getOrDefault(c, c));
bmpFont.draw(batch, mut, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width, Align.center, false);
}
}
/**
* Use the specified Batch to draw a String (often just one char long) in the specified rgba color, with x and y
* determining the world-space coordinates for the upper-left corner.
*
* @param batch the LibGDX Batch to do the drawing
* @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead.
* @param r 0.0 to 0.1 red value
* @param g 0.0 to 0.1 green value
* @param b 0.0 to 0.1 blue value
* @param a 0.0 to 0.1 alpha value
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
*/
public void draw(Batch batch, String s, float r, float g, float b, float a, float x, float y) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (s == null) {
Color orig = scc.filter(batch.getColor());
batch.setColor(r, g, b, a);
batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // descent * 1 / 3f
batch.setColor(orig);
} else if(s.length() > 0 && s.charAt(0) == '\0') {
Color orig = scc.filter(batch.getColor());
batch.setColor(r, g, b, a);
batch.draw(block, x, y - actualCellHeight, actualCellWidth * s.length(), actualCellHeight); // descent * 1 / 3f
batch.setColor(orig);
} else {
bmpFont.setColor(r, g, b, a);
mut.setCharAt(0, swap.getOrDefault(s.charAt(0), s.charAt(0)));
bmpFont.draw(batch, mut, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width, Align.center, false);
}
}
/**
* Use the specified Batch to draw a String (often just one char long) in the specified LibGDX Color, with x and y
* determining the world-space coordinates for the upper-left corner.
*
* @param batch the LibGDX Batch to do the drawing
* @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead.
* @param color the LibGDX Color to draw the char(s) with, all the same color
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
*/
public void draw(Batch batch, String s, Color color, float x, float y) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (s == null) {
Color orig = batch.getColor();
batch.setColor(scc.filter(color));
batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // descent * 1 / 3f
batch.setColor(orig);
} else if(s.length() > 0 && s.charAt(0) == '\0') {
Color orig = batch.getColor();
batch.setColor(scc.filter(color));
batch.draw(block, x, y - actualCellHeight, actualCellWidth * s.length(), actualCellHeight); // descent * 1 / 3f
batch.setColor(orig);
} else {
bmpFont.setColor(scc.filter(color));
mut.setCharAt(0, swap.getOrDefault(s.charAt(0), s.charAt(0)));
bmpFont.draw(batch, mut, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width, Align.center, false);
}
}
/**
* Use the specified Batch to draw a String (often just one char long) in the specified LibGDX Color, with x and y
* determining the world-space coordinates for the upper-left corner.
*
* @param batch the LibGDX Batch to do the drawing
* @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead.
* @param encodedColor the LibGDX Color to use, converted to float as by {@link Color#toFloatBits()}
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
*/
public void draw(Batch batch, String s, float encodedColor, float x, float y) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (s == null) {
float orig = batch.getPackedColor();
batch.setColor(encodedColor);
batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // descent * 1 / 3f
batch.setColor(orig);
} else if(s.length() > 0 && s.charAt(0) == '\0') {
float orig = batch.getPackedColor();
batch.setColor(encodedColor);
batch.draw(block, x, y - actualCellHeight, actualCellWidth * s.length(), actualCellHeight); // descent * 1 / 3f
batch.setColor(orig);
} else
{
colorFromFloat(bmpFont.getColor(), encodedColor);
mut.setCharAt(0, swap.getOrDefault(s.charAt(0), s.charAt(0)));
bmpFont.draw(batch, mut, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width, Align.center, false);
}
}
/**
* Use the specified Batch to draw a String (often just one char long) in the specified LibGDX Color, with x and y
* determining the world-space coordinates for the upper-left corner.
*
* @param batch the LibGDX Batch to do the drawing
* @param c the char to draw, often but not necessarily one char. Can be null to draw a solid block instead.
* @param encodedColor the LibGDX Color to use, converted to float as by {@link Color#toFloatBits()}
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
*/
public void draw(Batch batch, char c, float encodedColor, float x, float y) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (c == 0) {
float orig = batch.getPackedColor();
batch.setColor(encodedColor);
batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // descent * 1 / 3f
batch.setColor(orig);
} else
{
colorFromFloat(bmpFont.getColor(), encodedColor);
mut.setCharAt(0, swap.getOrDefault(c, c));
bmpFont.draw(batch, mut, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width, Align.center, false);
}
}
/**
* Use the specified Batch to draw a TextureRegion with the default tint color (white, so un-tinted), with x and y
* determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
* if its size does not match what this TextCellFactory uses for width and height.
*
* @param batch the LibGDX Batch to do the drawing
* @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
*/
public void draw(Batch batch, TextureRegion tr, float x, float y) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (tr == null) {
batch.draw(block, x, y - height, actualCellWidth, actualCellHeight);
} else {
batch.draw(tr, x, y - height, width, height);
}
}
/**
* Use the specified Batch to draw a TextureRegion tinted with the specified rgba color, with x and y
* determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
* if its size does not match what this TextCellFactory uses for width and height.
*
* @param batch the LibGDX Batch to do the drawing
* @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
* @param r 0.0 to 0.1 red value
* @param g 0.0 to 0.1 green value
* @param b 0.0 to 0.1 blue value
* @param a 0.0 to 0.1 alpha value
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
*/
public void draw(Batch batch, TextureRegion tr, float r, float g, float b, float a, float x, float y) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (tr == null) {
Color orig = batch.getColor();
batch.setColor(r, g, b, a);
batch.draw(block, x, y - height, actualCellWidth, actualCellHeight);
batch.setColor(orig);
} else {
Color orig = batch.getColor();
batch.setColor(r, g, b, a);
batch.draw(tr, x, y - height, width, height);
batch.setColor(orig);
}
}
/**
* Use the specified Batch to draw a TextureRegion tinted with the specified LibGDX Color, with x and y
* determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
* if its size does not match what this TextCellFactory uses for width and height.
*
* @param batch the LibGDX Batch to do the drawing
* @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
* @param color the LibGDX Color to draw the char(s) with, all the same color
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
*/
public void draw(Batch batch, TextureRegion tr, Color color, float x, float y) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (tr == null) {
Color orig = batch.getColor();
batch.setColor(scc.filter(color));
batch.draw(block, x, y - height, actualCellWidth, actualCellHeight);
batch.setColor(orig);
} else {
Color orig = batch.getColor();
batch.setColor(scc.filter(color));
batch.draw(tr, x, y - height, width, height);
batch.setColor(orig);
}
}
/**
* Use the specified Batch to draw a TextureRegion tinted with the specified encoded color as a float, with x and y
* determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
* if its size does not match what this TextCellFactory uses for width and height. Colors can be converted to and
* from floats using methods in SColor such as {@link SColor#floatGet(float, float, float, float)},
* {@link SColor#toFloatBits()}, {@link SColor#colorFromFloat(Color, float)}, and
* {@link SColor#lerpFloatColors(float, float, float)}.
*
* @param batch the LibGDX Batch to do the drawing
* @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
* @param encodedColor the float encoding a color (as ABGR8888; SColor can produce these) to draw the image with
* @param x x of the upper-left corner of the image in world coordinates.
* @param y y of the upper-left corner of the image in world coordinates.
*/
public void draw(Batch batch, TextureRegion tr, float encodedColor, float x, float y)
{
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (tr == null) {
float orig = batch.getPackedColor();
batch.setColor(encodedColor);
batch.draw(block, x, y - height, actualCellWidth, actualCellHeight);
batch.setColor(orig);
} else {
float orig = batch.getPackedColor();
batch.setColor(encodedColor);
batch.draw(tr, x, y - height, width, height);
batch.setColor(orig);
}
}
/**
* Use the specified Batch to draw a TextureRegion with the default tint color (white, so un-tinted), with x and y
* determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
* only if the supplied width and height do not match what its own dimensions are.
*
* @param batch the LibGDX Batch to do the drawing
* @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
* @param width the width of the TextureRegion or solid block in pixels.
* @param height the height of the TextureRegion or solid block in pixels.
*/
public void draw(Batch batch, TextureRegion tr, float x, float y, float width, float height) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (tr == null) {
batch.draw(block, x, y - height, width, height);
} else {
batch.draw(tr, x, y - height, width, height);
}
}
/**
* Use the specified Batch to draw a TextureRegion tinted with the specified rgba color, with x and y
* determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
* only if the supplied width and height do not match what its own dimensions are.
*
* @param batch the LibGDX Batch to do the drawing
* @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
* @param r 0.0 to 0.1 red value
* @param g 0.0 to 0.1 green value
* @param b 0.0 to 0.1 blue value
* @param a 0.0 to 0.1 alpha value
* @param x x of the upper-left corner of the region of text in world coordinates.
* @param y y of the upper-left corner of the region of text in world coordinates.
* @param width the width of the TextureRegion or solid block in pixels.
* @param height the height of the TextureRegion or solid block in pixels.
*/
public void draw(Batch batch, TextureRegion tr, float r, float g, float b, float a, float x, float y, float width, float height) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (tr == null) {
Color orig = batch.getColor();
batch.setColor(r, g, b, a);
batch.draw(block, x, y - height, width, height);
batch.setColor(orig);
} else {
Color orig = batch.getColor();
batch.setColor(r, g, b, a);
batch.draw(tr, x, y - height, width, height);
batch.setColor(orig);
}
}
/**
* Use the specified Batch to draw a TextureRegion tinted with the specified LibGDX Color, with x and y
* determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
* only if the supplied width and height do not match what its own dimensions are.
*
* @param batch the LibGDX Batch to do the drawing
* @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
* @param color the LibGDX Color to draw the image with, all the same color
* @param x x of the upper-left corner of the image in world coordinates.
* @param y y of the upper-left corner of the image in world coordinates.
* @param width the width of the TextureRegion or solid block in pixels.
* @param height the height of the TextureRegion or solid block in pixels.
*/
public void draw(Batch batch, TextureRegion tr, Color color, float x, float y, float width, float height) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (tr == null) {
Color orig = batch.getColor();
batch.setColor(scc.filter(color));
batch.draw(block, x, y - height, width, height);
batch.setColor(orig);
} else {
Color orig = batch.getColor();
batch.setColor(scc.filter(color));
batch.draw(tr, x, y - height, width, height);
batch.setColor(orig);
}
}
/**
* Use the specified Batch to draw a TextureRegion tinted with the specified LibGDX Color, with x and y
* determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched
* only if the supplied width and height do not match what its own dimensions are.
*
* @param batch the LibGDX Batch to do the drawing
* @param tr the TextureRegion to draw. Can be null to draw a solid block instead.
* @param encodedColor the float encoding a color (as ABGR8888; SColor can produce these) to draw the image with
* @param x x of the upper-left corner of the image in world coordinates.
* @param y y of the upper-left corner of the image in world coordinates.
* @param width the width of the TextureRegion or solid block in pixels.
* @param height the height of the TextureRegion or solid block in pixels.
*/
public void draw(Batch batch, TextureRegion tr, float encodedColor, float x, float y, float width, float height) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (tr == null) {
float orig = batch.getPackedColor();
batch.setColor(encodedColor);
batch.draw(block, x, y - height, width, height);
batch.setColor(orig);
} else {
float orig = batch.getPackedColor();
batch.setColor(encodedColor);
batch.draw(tr, x, y - height, width, height);
batch.setColor(orig);
}
}
/**
* Converts a String into a Label, or if the argument s is null, creates an Image of a solid block. Can be used
* for preparing glyphs for animation effects.
* @param s a String to make into an Actor, which can be null for a solid block.
* @return the Actor, with no position set.
*/
public Label makeWrappingString(String s) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (s == null) {
s = "";
}
Label lb = new Label(s, style);
lb.setWrap(true);
// lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return lb;
}
/**
* Converts a String into a Label, or if the argument s is null, creates an Image of a solid block. Can be used
* for preparing glyphs for animation effects, and is used internally for this purpose.
* @param s a String to make into an Actor, which can be null for a solid block.
* @param color a Color to tint s with.
* @return the Actor, with no position set.
*/
public Actor makeActor(String s, Color color) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (s == null) {
Image im = new Image(block);
im.setColor(scc.filter(color));
//im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f));
im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
} else if(s.length() > 0 && s.charAt(0) == '\0') {
Image im = new Image(block);
im.setColor(scc.filter(color));
//im.setSize(width * s.length(), height - MathUtils.ceil(bmpFont.getDescent() / 2f));
im.setSize(actualCellWidth * s.length(), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
} else {
mut.setCharAt(0, swap.getOrDefault(s.charAt(0), s.charAt(0)));
Label lb = new Label(mut, style);
//lb.setFontScale(bmpFont.getData().scaleX, bmpFont.getData().scaleY);
lb.setSize(width * s.length(), height - descent); //+ lineTweak * 1f
lb.setColor(scc.filter(color));
// lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return lb;
}
}
/**
* Converts a String into a ColorChangeLabel, or if the argument s is null, creates a ColorChangeImage of a solid
* block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The
* ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor,
* though they are affected by their setColors methods. Their color change is not considered an animation for the
* purposes of things like SquidPanel.hasActiveAnimations() .
* @param s a String to make into an Actor, which can be null for a solid block.
* @param colors a List of Color to tint s with, looping through all elements in the list each second
* @return the Actor, with no position set.
*/
public Actor makeActor(String s, Collection<Color> colors) {
return makeActor(s, colors, 2f, false);
}
/**
* Converts a String into a ColorChangeLabel, or if the argument s is null, creates a ColorChangeImage of a solid
* block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The
* ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor,
* though they are affected by their setColors methods. Their color change is not considered an animation for the
* purposes of things like SquidPanel.hasActiveAnimations() .
* @param s a String to make into an Actor, which can be null for a solid block.
* @param colors a List of Color to tint s with, looping through all elements in the list each second
* @param loopTime the amount of time, in seconds, to spend looping through all colors in the list
* @return the Actor, with no position set.
*/
public Actor makeActor(String s, Collection<Color> colors, float loopTime)
{
return makeActor(s, colors, loopTime, false);
}
/**
* Converts a String into a ColorChangeLabel, or if the argument s is null, creates a ColorChangeImage of a solid
* block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The
* ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor,
* though they are affected by their setColors methods. Their color change is not considered an animation for the
* purposes of things like SquidPanel.hasActiveAnimations() .
* @param s a String to make into an Actor, which can be null for a solid block.
* @param colors a List of Color to tint s with, looping through all elements in the list each second
* @param loopTime the amount of time, in seconds, to spend looping through all colors in the list
* @return the Actor, with no position set.
*/
public Actor makeActor(String s, Collection<Color> colors, float loopTime, boolean doubleWidth) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
ArrayList<Color> colors2 = null;
if(colors != null && !colors.isEmpty())
{
colors2 = new ArrayList<>(colors.size());
for (Color c : colors) {
colors2.add(scc.filter(c));
}
}
if (s == null) {
ColorChangeImage im = new ColorChangeImage(block, loopTime, doubleWidth, colors2);
//im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f));
im.setSize(actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
} else if(s.length() > 0 && s.charAt(0) == '\0') {
ColorChangeImage im = new ColorChangeImage(block, loopTime, doubleWidth, colors2);
//im.setSize(width * s.length(), height - MathUtils.ceil(bmpFont.getDescent() / 2f));
im.setSize(actualCellWidth * s.length() * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
} else {
mut.setCharAt(0, swap.getOrDefault(s.charAt(0), s.charAt(0)));
ColorChangeLabel lb = new ColorChangeLabel(mut, style, loopTime, doubleWidth, colors2);
lb.setSize(width * s.length(), height - descent); //+ lineTweak * 1f
// lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return lb;
}
}
/**
* Converts a char into a Label, or if the argument c is '\0', creates an Image of a solid block. Can be used
* for preparing glyphs for animation effects, and is used internally for this purpose.
* @param c a char to make into an Actor, which can be the character with Unicode value 0 for a solid block.
* @param color a Color to tint c with.
* @return the Actor, with no position set.
*/
public Actor makeActor(char c, Color color) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (c == 0) {
Image im = new Image(block);
im.setColor(scc.filter(color));
//im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f));
im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
} else {
mut.setCharAt(0, swap.getOrDefault(c, c));
Label lb = new Label(mut, style);
//lb.setFontScale(bmpFont.getData().scaleX, bmpFont.getData().scaleY);
lb.setSize(width, height - descent); //+ lineTweak * 1f
lb.setColor(scc.filter(color));
// lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return lb;
}
}
/**
* Converts a char into a Label, or if the argument c is '\0', creates an Image of a solid block. Can be used
* for preparing glyphs for animation effects, and is used internally for this purpose. Instead of a libGDX Color
* object, this takes an encoded float that represents a color as libGDX often does internally, ABGR-packed format.
* You can use various methods in SColor to produce these, like {@link SColor#floatGet(float, float, float, float)}
* or {@link Color#toFloatBits()}.
* @param c a char to make into an Actor, which can be the character with Unicode value 0 for a solid block.
* @param encodedColor an ABGR packed float (as produced by {@link SColor#floatGet(float, float, float, float)}) to use as c's color
* @return the Actor, with no position set.
*/
public Actor makeActor(char c, float encodedColor) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (c == 0) {
Image im = new Image(block);
Color.abgr8888ToColor(im.getColor(), encodedColor);
//im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f));
im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
} else {
mut.setCharAt(0, swap.getOrDefault(c, c));
Label lb = new Label(mut, style);
//lb.setFontScale(bmpFont.getData().scaleX, bmpFont.getData().scaleY);
lb.setSize(width, height - descent); //+ lineTweak * 1f
Color.abgr8888ToColor(lb.getColor(), encodedColor);
// lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return lb;
}
}
/**
* Converts a char into a ColorChangeLabel, or if the argument c is '\0', creates a ColorChangeImage of a solid
* block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The
* ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor,
* though they are affected by their setColors methods. Their color change is not considered an animation for the
* purposes of things like SquidPanel.hasActiveAnimations() .
* @param c a char to make into an Actor, which can be the character with Unicode value 0 for a solid block.
* @param colors a List of Color to tint c with, looping through all elements in the list each second
* @return the Actor, with no position set.
*/
public Actor makeActor(char c, Collection<Color> colors) {
return makeActor(c, colors, 2f, false);
}
/**
* Converts a char into a ColorChangeLabel, or if the argument c is '\0', creates a ColorChangeImage of a solid
* block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The
* ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor,
* though they are affected by their setColors methods. Their color change is not considered an animation for the
* purposes of things like SquidPanel.hasActiveAnimations() .
* @param c a char to make into an Actor, which can be the character with Unicode value 0 for a solid block.
* @param colors a List of Color to tint c with, looping through all elements in the list each second
* @param loopTime the amount of time, in seconds, to spend looping through all colors in the list
* @return the Actor, with no position set.
*/
public Actor makeActor(char c, Collection<Color> colors, float loopTime)
{
return makeActor(c, colors, loopTime, false);
}
/**
* Converts a char into a ColorChangeLabel, or if the argument c is '\0', creates a ColorChangeImage of a solid
* block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The
* ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor,
* though they are affected by their setColors methods. Their color change is not considered an animation for the
* purposes of things like SquidPanel.hasActiveAnimations() .
* @param c a char to make into an Actor, which can be the character with Unicode value 0 for a solid block.
* @param colors a List of Color to tint c with, looping through all elements in the list each second
* @param loopTime the amount of time, in seconds, to spend looping through all colors in the list
* @return the Actor, with no position set.
*/
public Actor makeActor(char c, Collection<Color> colors, float loopTime, boolean doubleWidth) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
ArrayList<Color> colors2 = null;
if(colors != null && !colors.isEmpty())
{
colors2 = new ArrayList<>(colors.size());
for (Color color : colors) {
colors2.add(scc.filter(color));
}
}
if (c == 0) {
ColorChangeImage im = new ColorChangeImage(block, loopTime, doubleWidth, colors2);
//im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f));
im.setSize(actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
} else {
mut.setCharAt(0, swap.getOrDefault(c, c));
ColorChangeLabel lb = new ColorChangeLabel(mut, style, loopTime, doubleWidth, colors2);
lb.setSize(width, height - descent); //+ lineTweak * 1f
// lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return lb;
}
}
public Actor makeActor(TextureRegion tr, Collection<Color> colors)
{
return makeActor(tr, colors, 2f, false);
}
public Actor makeActor(TextureRegion tr, Collection<Color> colors, float loopTime)
{
return makeActor(tr, colors, loopTime, false);
}
/**
* Converts a TextureRegion into a ColorChangeImage that will cycle through the given colors.
* ColorChange classes will rotate between all colors given in the List each loopTime, and are not affected by
* setColor, though they are affected by their setColors methods. Their color change is not considered an animation
* for the purposes of things like SquidPanel.hasActiveAnimations() .
* @param tr a TextureRegion to make into an Actor, which can be null for a solid block.
* @param colors a List of Color to tint c with, looping through all elements in the list each second
* @param loopTime the amount of time, in seconds, to spend looping through all colors in the list
* @return the Actor, with no position set.
*/
public Actor makeActor(TextureRegion tr, Collection<Color> colors, float loopTime, boolean doubleWidth){
return makeActor(tr, colors, loopTime, doubleWidth,
actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0));
}
/**
* Converts a TextureRegion into a ColorChangeImage that will cycle through the given colors.
* ColorChange classes will rotate between all colors given in the List each loopTime, and are not affected by
* setColor, though they are affected by their setColors methods. Their color change is not considered an animation
* for the purposes of things like SquidPanel.hasActiveAnimations() .
* @param tr a TextureRegion to make into an Actor, which can be null for a solid block.
* @param colors a List of Color to tint c with, looping through all elements in the list each second
* @param loopTime the amount of time, in seconds, to spend looping through all colors in the list
* @return the Actor, with no position set.
*/
public Actor makeActor(TextureRegion tr, Collection<Color> colors, float loopTime, boolean doubleWidth,
float width, float height){
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
ArrayList<Color> colors2 = null;
if(colors != null && !colors.isEmpty())
{
colors2 = new ArrayList<>(colors.size());
for (Color color : colors) {
colors2.add(scc.filter(color));
}
}
if (tr == null) {
ColorChangeImage im = new ColorChangeImage(block, loopTime, doubleWidth, colors2);
im.setSize(width, height);
return im;
} else {
ColorChangeImage im = new ColorChangeImage(tr, loopTime, doubleWidth, colors2);
im.setSize(width, height);
return im;
}
}
/**
* Creates a ColorChangeImage Actor that should look like the glyph '^' in this font, but will be rotate-able. The
* ColorChange classes will rotate between all colors given in the List in the given amount of loopTime, and are not
* affected by setColor, though they are affected by their setColors methods. Their color change is not considered
* an animation for the purposes of things like SquidPanel.hasActiveAnimations() .
* @param colors a List of Color to tint s with, looping through all elements in the list each second
* @param loopTime the amount of time, in seconds, to spend looping through all colors in the list
* @return the Actor, with no position set.
*/
public Image makeDirectionMarker(Collection<Color> colors, float loopTime, boolean doubleWidth) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
ArrayList<Color> colors2 = null;
if (colors != null && !colors.isEmpty()) {
colors2 = new ArrayList<>(colors.size());
for (Color c : colors) {
colors2.add(scc.filter(c));
}
}
ColorChangeImage im = new ColorChangeImage(dirMarker, loopTime, doubleWidth,
actualCellWidth, actualCellHeight + (distanceField ? 1 : 0), colors2);
im.setAlign(2);
im.setSize(actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
return im;
}
/**
* Creates a Image Actor that should look like the glyph '^' in this font, but will be rotate-able.
* @param color a Color to tint the '^' with
* @return the Actor, with no position set.
*/
public Image makeDirectionMarker(Color color) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
Image im = new Image(dirMarker);
im.setColor(scc.filter(color));
im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
im.setOrigin(1); //center
return im;
}
public ColorChangeImage makeGlyphImage(char glyph, Color color)
{
return makeGlyphImage(glyph, color, false);
}
public ColorChangeImage makeGlyphImage(char glyph, Color color, boolean doubleWidth)
{
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
TextureRegion tr;
if (glyphTextures.containsKey(glyph))
{
tr = glyphTextures.get(glyph);
}
else
{
BitmapFont.Glyph g = bmpFont.getData().getGlyph(glyph);
tr = new TextureRegion(bmpFont.getRegion(g.page), g.srcX, g.srcY, g.width, g.height);
glyphTextures.put(glyph, tr);
}
ColorChangeImage im = new ColorChangeImage(tr, 1, doubleWidth,
actualCellWidth, actualCellHeight + (distanceField ? 1 : 0), Collections.singletonList(scc.filter(color)));
im.setAlign(2);
im.setSize(actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
return im;
}
public ColorChangeImage makeGlyphImage(char glyph, Collection<Color> colors, float loopTime, boolean doubleWidth) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
TextureRegion tr;
if (glyphTextures.containsKey(glyph))
{
tr = glyphTextures.get(glyph);
}
else
{
BitmapFont.Glyph g = bmpFont.getData().getGlyph(glyph);
tr = new TextureRegion(bmpFont.getRegion(g.page), g.srcX, g.srcY, g.width, g.height);
glyphTextures.put(glyph, tr);
}
ArrayList<Color> colors2 = null;
if (colors != null && !colors.isEmpty()) {
colors2 = new ArrayList<>(colors.size());
for (Color c : colors) {
colors2.add(scc.filter(c));
}
}
ColorChangeImage im = new ColorChangeImage(tr, loopTime, doubleWidth,
actualCellWidth, actualCellHeight + (distanceField ? 1 : 0), colors2);
im.setAlign(2);
im.setSize(actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f
return im;
}
/**
* Converts a TextureRegion into an Image, or if the argument s is null, creates an Image of a solid block. Can be
* used for preparing images for animation effects. Stretches the TextureRegion to match a single cell's dimensions.
* @param tr a TextureRegion to make into an Actor, which can be null for a solid block.
* @param color a Color to tint tr with.
* @return the Actor, with no position set.
*/
public Actor makeActor(TextureRegion tr, Color color) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (tr == null) {
Image im = new Image(block);
im.setColor(scc.filter(color));
im.setSize(width, height);
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
} else {
Image im = new Image(tr);
im.setColor(scc.filter(color));
im.setSize(width, height);
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
}
}
/**
* Converts a TextureRegion into an Image, or if the argument s is null, creates an Image of a solid block. Can be
* used for preparing images for animation effects. Ensures the returned Image has the given width and height.
* @param tr a TextureRegion to make into an Actor, which can be null for a solid block.
* @param color a Color to tint tr with.
* @return the Actor, with no position set.
*/
public Actor makeActor(TextureRegion tr, Color color, float width, float height) {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
if (tr == null) {
Image im = new Image(block);
im.setColor(scc.filter(color));
im.setSize(width, height);
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
} else {
Image im = new Image(tr);
im.setColor(scc.filter(color));
im.setSize(width, height);
// im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center);
return im;
}
}
/**
* Returns a solid block of white, 1x1 pixel in size; can be drawn at other sizes by Batch.
*
* @return a white 1x1 pixel Texture.
*/
public Texture getSolid() {
if (!initialized) {
throw new IllegalStateException("This factory has not yet been initialized!");
}
return block;
}
public boolean isDistanceField() {
return distanceField;
}
public float getDistanceFieldScaleX() {
return distanceFieldScaleX;
}
public float getDistanceFieldScaleY() {
return distanceFieldScaleY;
}
/**
* If this uses a distance field font, the smoothing multiplier affects how crisp or blurry lines are, with higher
* numbers generally resulting in more crisp fonts, but numbers that are too high cause jagged aliasing.
* @return the current smoothing multiplier as a float, which starts at 1f.
*/
public float getSmoothingMultiplier() {
return smoothingMultiplier;
}
/**
* If this uses a distance field font, the smoothing multiplier affects how crisp or blurry lines are, with higher
* numbers generally resulting in more crisp fonts, but numbers that are too high cause jagged aliasing.
* @param smoothingMultiplier the new value for the smoothing multiplier as a float; should be fairly close to 1f.
* @return this for chaining
*/
public TextCellFactory setSmoothingMultiplier(float smoothingMultiplier) {
this.smoothingMultiplier = smoothingMultiplier;
return this;
}
/**
* If using a distance field font, you MUST call this at some point while the batch has begun, or use code that
* calls it for you (which is now much of SquidLib). A typical point to call it is in the
* "void draw(Batch batch, float parentAlpha)" method or an overriding method for a Scene2D class. You should call
* configureShader rarely, typically only a few times per frame if there are no images to render, and this means the
* logical place to call it is in the outermost Group that contains any SquidPanel objects or other widgets. If you
* have multipleTextCellFactory objects, each one needs to have configureShader called before it is used to draw.
* <br>
* SquidLayers and SquidPanel already call this method in their draw overrides, so you don't need to call this
* manually if you use SquidLayers or SquidPanel.
* <br>
* If you don't use a distance field font, you don't need to call this, but calling it won't cause problems.
*
* @param batch the Batch, such as a SpriteBatch, to configure to render distance field fonts if necessary.
*/
public void configureShader(Batch batch) {
if (initialized && distanceField) {
batch.setShader(shader);
shader.setUniformf("u_smoothing", 0.2f / (3.5f * smoothingMultiplier * bmpFont.getData().scaleX));
}
}
/**
* Releases all resources of this object.
*/
@Override
public void dispose() {
if(bmpFont != null) bmpFont.dispose();
if(block != null) block.dispose();
}
/**
* Gets the descent of this TextCellFactory's BitmapFont, which may be useful for layout outside this class.
* @return the descent of the BitmapFont this object uses
*/
public float getDescent() {
return descent;
}
public char getDirectionGlyph() {
return directionGlyph;
}
public TextCellFactory setDirectionGlyph(char directionGlyph) {
this.directionGlyph = directionGlyph;
return this;
}
/**
* Adds a pair of Strings (typically both with length 1) as a replacement pair, so when the find String is requested
* to be drawn, the replace String is used instead. Swaps are used when drawing text in each cell in SquidPanel and
* related classes, so Strings longer than 1 char are effectively disregarded beyond the first char.
* <br>
* This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep
* water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something
* that would be drawn. Replacements will not be chained; that is, if you {@code addSwap("^", ",")} and also
* {@code addSwap(",", ":")}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn
* as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use
* swapping, like a top-down char-based map, and elements that should not, like those that display normal text.
* @param find the requested String that will be changed
* @param replace the replacement String that will be used in place of find
* @return this for chaining
*/
public TextCellFactory addSwap(String find, String replace)
{
if(find == null || replace == null || find.isEmpty() || replace.isEmpty() || find.charAt(0) == 0)
return this;
swap.put(find.charAt(0), replace.charAt(0));
return this;
}
/**
* Adds a pair of chars as a replacement pair, so when the find char is requested to be drawn, the replace char is
* used instead.
* <br>
* This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep
* water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something
* that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also
* {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn
* as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use
* swapping, like a top-down char-based map, and elements that should not, like those that display normal text.
* @param find the requested char that will be changed (converted to a length-1 String)
* @param replace the replacement char that will be used in place of find (converted to a length-1 String)
* @return this for chaining
*/
public TextCellFactory addSwap(char find, char replace)
{
if(find == 0)
return this;
swap.put(find, replace);
return this;
}
/**
* Removes the replacement pair, if present, that searches for the given key, find. Swaps are used when drawing text
* in each cell in SquidPanel and related classes, so Strings longer than 1 char are effectively disregarded beyond
* the first char.
* <br>
* This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep
* water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something
* that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also
* {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn
* as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use
* swapping, like a top-down char-based map, and elements that should not, like those that display normal text.
* @param find the String that would be changed in the replacement pair
* @return this for chaining
*/
public TextCellFactory removeSwap(String find)
{
if(find != null && !find.isEmpty() && find.charAt(0) != 0)
swap.remove(find.charAt(0));
return this;
}
/**
* Removes the replacement pair, if present, that searches for the given key, find.
* <br>
* This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep
* water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something
* that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also
* {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn
* as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use
* swapping, like a top-down char-based map, and elements that should not, like those that display normal text.
* @return this for chaining
*/
public TextCellFactory removeSwap(char find)
{
swap.remove(find);
return this;
}
/**
* Gets the current mapping of "swaps", or replacement pairs, to replace keys requested for drawing with their
* values in the OrderedMap.
* <br>
* This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep
* water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something
* that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also
* {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn
* as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use
* swapping, like a top-down char-based map, and elements that should not, like those that display normal text.
* @return the mapping of replacement pairs
*/
public OrderedMap<Character, Character> getAllSwaps() {
return swap;
}
/**
* Sets the mapping of replacement pairs to a different one as a Map of Character keys to String values.
* <br>
* This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep
* water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something
* that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also
* {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn
* as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use
* swapping, like a top-down char-based map, and elements that should not, like those that display normal text.
* @param swaps the Map of replacement pairs; keys requested for drawing will be replaced with their values
* @return this for chaining
*/
public TextCellFactory setAllSwaps(OrderedMap<Character, Character> swaps) {
swap.clear();
for (int i = 0; i < swaps.size(); i++) {
if(!swaps.keyAt(i).equals('\0'))
swap.put(swaps.keyAt(i), swaps.getAt(i));
}
return this;
}
/**
* Appends to the mapping of replacement pairs, adding or replacing any entries in the current mapping with the
* entries in a Map of Character keys to String values.
* <br>
* This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep
* water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something
* that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also
* {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn
* as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use
* swapping, like a top-down char-based map, and elements that should not, like those that display normal text.
* @param swaps the Map of replacement pairs to add; keys requested for drawing will be replaced with their values
* @return this for chaining
*/
public TextCellFactory addSwaps(OrderedMap<Character, Character> swaps) {
for (int i = 0; i < swaps.size(); i++) {
if(!swaps.keyAt(i).equals('\0'))
swap.put(swaps.keyAt(i), swaps.getAt(i));
}
return this;
}
/**
* Clears all replacement pairs this has been told to swap.
* <br>
* This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep
* water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something
* that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also
* {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn
* as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use
* swapping, like a top-down char-based map, and elements that should not, like those that display normal text.
* @return this for chaining
*/
public TextCellFactory clearSwaps()
{
swap.clear();
return this;
}
}